﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Phidgets;
using Phidgets.Events;

namespace InterValometer
{
    public partial class Form1 : Form
    {
        InterValometerTimer pd, ex, fd;
        int ne, exp;
        int PreDelay;
        int ExpDur;
        int FrmDel;
        int NumExp;
        IR ir;

        String cd_Shutter = "0x5a5c7";      // 0101 1010
        String cd_TwoSecond = "0x765c7";    // 0111 0110
        String cd_SlideShow = "0x715c7";    // 0111 0001
        String cd_Display = "0x145c7";      // 0001 0100
        String cd_Histogram = "0x6c5c7";    // 0110 1100
        String cd_ZoomIn = "0x295c7";       // 0010 1001
        String cd_Multi = "0x025c7";        // 0000 0010
        String cd_Rotate = "0x265c7";       // 0010 0110
        String cd_ZoomOut = "0x695C7";      // 0110 1001
        String cd_Play = "0x1e5c7";         // 0001 1110
        String cd_Menu = "0x0e5c7";         // 0000 1110
        String cd_Up = "0x2e5c7";           // 0010 1110
        String cd_Trash = "0x5e5c7";        // 0101 1110
        String cd_Left = "0x3e5c7";         // 0011 1110
        String cd_Middle = "0x4e5c7";       // 0100 1110
        String cd_Right = "0x7e5c7";        // 0111 1110
        String cd_Print = "0x445c7";        // 0100 0100
        String cd_Down = "0x6e5c7";         // 0110 1110

        String cd_TwoSecondDelay = "0x765c7";
        String cd_TriggerShutter = "0x5a5c7";
        String cd_PlayCommand = "0x1e5c7";

        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            // intialize all global variables
            PreDelay = 0;
            ExpDur = 0;
            FrmDel = 0;
            NumExp = 0;
            this.IsExposing = false;
            this.IRAttached = false;

            timer1.Interval = 10;
            butn_ShutterTrigger.Enabled = true;
            butn_PlaySequence.Enabled = true;

            /* setup Phidget IR */
            ir = new IR();
            ir.Attach += new AttachEventHandler(ir_Attach);
            ir.Detach += new DetachEventHandler(ir_Detach);
            ir.open();

            toolStripStatusLabel3.Enabled = false;
            toolStripStatusLabel3.Text = "CIR";
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Hide();
            }
        }

        /// <summary>
        /// SendCode
        /// </summary>
        private void SendCode(string com_code)
        {
            // Header: 2400, 600  -  2380, 590
            // Zero  :  600, 600  -   600, 590
            // One   : 1200, 600  -  1180, 590
            // Trail : 1200       -  1180
            // Gap   : 11250      -  11280
            // Repeat:            -  9078, 2345, 593
            try
            {
                // Sony NEX IR Code
                IRCodeInfo codeInfo = new IRCodeInfo(
                    IRCodeInfo.IREncoding.Space,
                    19,
                    new int[] { 2400, 600 },
                    new int[] { 600, 600 },
                    new int[] { 1200, 600 },
                    1280,
                    11250
                    //new int[] { 9078, 2345, 593 }
                );

                // transmit IR command code five times to ensure shutter has been triggered
                // the rmt-dslr1 sends each code 5 times as well
                ir.transmit(new IRCode(com_code, 19), codeInfo);
                ir.transmit(new IRCode(com_code, 19), codeInfo);
                ir.transmit(new IRCode(com_code, 19), codeInfo);
                ir.transmit(new IRCode(com_code, 19), codeInfo);
                ir.transmit(new IRCode(com_code, 19), codeInfo);
            }
            catch (PhidgetException ex)
            {
                Console.WriteLine(ex.Description);
            }
        }

        /// <summary>
        /// Triggered when the Phidgets IR transceiver has been attached
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ir_Attach(object sender, AttachEventArgs e)
        {
            this.IRAttached = true;
            IR attached = (IR)sender;
            toolStripStatusLabel1.Enabled = true;

            // now that we have the IR transceiver we can allow shutter and play buttons
            butn_PlaySequence.Enabled = true;
            butn_ShutterTrigger.Enabled = true;
        }

        /// <summary>
        /// ir_Detach
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ir_Detach(object sender, DetachEventArgs e)
        {
            this.IRAttached = false;
            IR detached = (IR)sender;
            toolStripStatusLabel1.Enabled = false;

            // flag that the IR transceiver has been detached so active sequence will be stopped
            this.IsExposing = false;

            // lost the IR transceiver so disable play and shutter buttons
            butn_PlaySequence.Enabled = false;
            butn_ShutterTrigger.Enabled = false;
        }

        /// <summary>
        /// Pre-Delay Timer
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            // perform action on pre-delay timer
            if (pd.Enabled)
            {
                // not expired, perform updates
                if (!pd.Expired)
                {
                    pd.Update();
                    toolStripStatusLabel1.Text = "Pre-Delay:";
                    toolStripStatusLabel2.Text = String.Format("{0:00.0}s", pd.Elapsed / 1000);
                }
                // expired, disable pre-delay timer and start exposure timer
                else
                {
                    textBox1.Text += String.Format("PreDelay Expired: {0}\r\n", DateTime.Now.Ticks);
                    pd.Enabled = false;

                    // number of exposures we've taken
                    exp++;
                    toolStripStatusLabel1.Text = String.Format("Exposure: {0:00} of {1:00}", exp, Convert.ToInt32(nupd_SEQ_NUM_EXP.Value));

                    // trigger shutter
                    this.SendCode(cd_TriggerShutter);
                    textBox1.Text += String.Format("Exposure Started: {0}\r\n", DateTime.Now.Ticks);
                    ex.Start();
                }
            }
            // perform action on exposure timer
            else if (ex.Enabled)
            {
                // not expired, perform updates
                if (!ex.Expired)
                {
                    ex.Update();
                    toolStripStatusLabel2.Text = String.Format("{0:00.0}s", ex.Elapsed / 1000);
                }
                // expired, disable exposure timer and start frame delay timer
                else
                {
                    textBox1.Text += String.Format("Exposure Expired: {0}\r\n", DateTime.Now.Ticks);
                    ex.Enabled = false;

                    // end exposure
                    this.SendCode(cd_TriggerShutter);
                    textBox1.Text += String.Format("FrameDelay Started: {0}\r\n", DateTime.Now.Ticks);
                    fd.Start();
                }
            }
            // perform action on frame delay timer
            else if (fd.Enabled)
            {
                // do we still have exposure to take?
                if ((ne - exp) > 0)
                {
                    // not expired, perform updates
                    if (!fd.Expired)
                    {
                        fd.Update();
                        toolStripStatusLabel1.Text = "Frame Delay:";
                        toolStripStatusLabel2.Text = String.Format("{0:00.0}s", fd.Elapsed / 1000);
                    }
                    // expired, reset timers and start exposure timer
                    else
                    {
                        textBox1.Text += String.Format("FrameDelay Expired: {0}\r\n", DateTime.Now.Ticks);
                        fd.Enabled = false;

                        fd.Reset();
                        ex.Reset();

                        // starting new exposure
                        exp++;
                        toolStripStatusLabel1.Text = String.Format("Exposure: {0:00} of {1:00}", exp, Convert.ToInt32(nupd_SEQ_NUM_EXP.Value));

                        // start exposure
                        this.SendCode(cd_TriggerShutter);
                        textBox1.Text += String.Format("Exposure Started: {0}\r\n", DateTime.Now.Ticks);
                        ex.Start();
                    }
                }
                // done with everything, stop primary timer and reset sequence timers so we can start again sometime
                else
                {
                    timer1.Enabled = false;
                    pd.Reset();
                    //toolStripStatusLabel5.Text = String.Format("Elapsed: {0:000.00000}", ex.Elapsed);
                    ex.Reset();
                    fd.Reset();
                    exp = 0;
                    butn_StopSequence.Enabled = false;
                    butn_PlaySequence.Enabled = true;
                    butn_ShutterTrigger.Enabled = true;
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void notifyIcon1_DoubleClick(object sender, EventArgs e)
        {
            if (!this.Visible)
            {
                this.Show();
                this.WindowState = FormWindowState.Normal;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void showFormToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!this.Visible)
            {
                this.Show();
                this.WindowState = FormWindowState.Normal;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void hideFormToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.Visible)
                this.Hide();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exitToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            // If form is dirty prompt the user to save changes then exit properly
            this.Close();
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            notifyIcon1.Dispose();
            ir.close();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chbx_SEQ_BLB_MOD_CheckedChanged(object sender, EventArgs e)
        {
            // If bulb mode is off, exposure is set on camera so disable option
            if (chbx_SEQ_BLB_MOD.Checked)
            {
                nupd_SEQ_EXP_DUR.Enabled = true;
            }
            else
            {
                nupd_SEQ_EXP_DUR.Enabled = false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void butn_PlaySequence_Click(object sender, EventArgs e)
        {
            // allocate new timers with current values
            pd = new InterValometerTimer(Convert.ToInt32(nupd_SEQ_PRE_DEL.Value));
            ex = new InterValometerTimer(Convert.ToInt32(nupd_SEQ_EXP_DUR.Value));
            fd = new InterValometerTimer(Convert.ToInt32(nupd_SEQ_FRM_DEL.Value));
            ne = Convert.ToInt32(nupd_SEQ_NUM_EXP.Value);

            // start pre-delay and enable primary timer
            pd.Start();
            textBox1.Text += String.Format("PreDelay Started: {0}\r\n", DateTime.Now.Ticks);
            timer1.Enabled = true;

            this.IsExposing = true;
            butn_ShutterTrigger.Enabled = false;
            butn_StopSequence.Enabled = true;
            butn_PlaySequence.Enabled = false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void butn_StopSequence_Click(object sender, EventArgs e)
        {
            // disable timer and set global state
            this.IsExposing = false;
            timer1.Enabled = false;

            // reset timers so they can be played again
            pd.Reset();
            ex.Reset();
            fd.Reset();
            exp = 0;

            // cleanup statusbar
            toolStripStatusLabel2.Text = "    ";
            toolStripStatusLabel3.Text = "    ";
            //toolStripStatusLabel4.Text = "    ";

            // reset toolbar button states
            butn_ShutterTrigger.Enabled = true;
            butn_StopSequence.Enabled = false;
            butn_PlaySequence.Enabled = true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void butn_ShutterTrigger_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_TriggerShutter);
        }

        bool IsExposing { get; set; }
        bool IRAttached { get; set; }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_TwoSecondDelay);
        }

        private void butn_Shutter_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Shutter);
        }

        private void butn_TwoSecond_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_TwoSecond);
        }

        private void butn_Slideshow_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_SlideShow);
        }

        private void butn_Display_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Display);
        }

        private void butn_Histogram_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Histogram);
        }

        private void butn_ZoomIn_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_ZoomIn);
        }

        private void butn_Multimode_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Multi);
        }

        private void butn_Rotate_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Rotate);
        }

        private void butn_ZoomOut_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_ZoomOut);
        }

        private void butn_Play_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Play);
        }

        private void butn_Menu_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Menu);
        }

        private void butn_Up_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Up);
        }

        private void butn_Trash_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Trash);
        }

        private void butn_Left_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Left);
        }

        private void butn_Middle_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Middle);
        }

        private void butn_Right_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Right);
        }

        private void butn_Print_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Print);
        }

        private void butn_Down_Click(object sender, EventArgs e)
        {
            this.SendCode(cd_Down);
        }
    }
}
